package com.spzx.product.lock.impl;

import com.spzx.common.core.utils.StringUtils;
import com.spzx.product.lock.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

//测试代码，从redis中获取num，把num+1再放回redis中去
public class TestServiceImpl implements TestService {

    @Autowired
    //提供了对redis数据库中字符串类型的各种操作
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public synchronized void testLock() {
        //从redis中获取数据
        String num = stringRedisTemplate.opsForValue().get("num");
        //判断
        if (StringUtils.isBlank(num)){
            return;
        }
        //若redis中有num这个数据，那就+1然后放回redis

//        Integer value =Integer.valueOf(num+1);
        int value = Integer.parseInt(num);
        stringRedisTemplate.opsForValue().set("num",String.valueOf(++value));
        System.out.println("num值为："+value);
    }

    //setnx分布式锁简单实现
    @Override
    public void testLock2() {
        //加锁  //设置过期时间,保证锁最终能释放
        String uuid = UUID.randomUUID().toString().replace("-", "");
        Boolean absent = stringRedisTemplate.opsForValue()
                .setIfAbsent("lock", uuid,5, TimeUnit.MINUTES);

        if(absent){
            try {
                //说明加锁成功
                String num = stringRedisTemplate.opsForValue().get("num");
                if(StringUtils.isBlank(num)){
                    return;
                }
                int value = Integer.parseInt(num);
                stringRedisTemplate.opsForValue().set("num",String.valueOf(++value));
            }finally {
                //判断是否是自己的锁，是自己的锁再释放
//                if(uuid.equals(stringRedisTemplate.opsForValue().get("lock"))){
//                    //释放锁
//                    stringRedisTemplate.delete("lock");
//                }

                //lua脚本保证原子性   释放锁
                //创建对象
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                //lua脚本
                String script = "if redis.call(\"get\",KEYS[1])==ARGV[1]\n" +
                        "then\n" + "return redis.call(\"get\",KEYS[1])"+
                        "else\n" +"return 0\n"+
                        "end";
                redisScript.setScriptText(script);
                redisScript.setResultType(Long.class);
                //redisTemplate执行lua脚本
                stringRedisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
            }

        }else {
            try {
                //得不到锁就自旋
                Thread.sleep(1000);
                this.testLock2();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }



}
